#include <iostream>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <pthread.h>
#include <unistd.h>
#include <signal.h>
#include <list>
#include <sqlite3.h>

#include <thread>

#include <sqlite3.h>
#include <string>

struct user_inf
{
    int ID;
    char name[30];
    struct sockaddr_in send_addr;
};

#define RECV_PORT 2000 // 接收端口

#define _DATAPAEK 10   // 数据包最大携带数据大小 (测试为10字节)
#define HEARTBEAT 0x44 // 心跳包,用于服务器更新用户收发的端口信息
#define SENDTO 0x55    // 握手
#define SENDOUT 0x7f   // 通信结束

#define ADDGREP 0x0A // 加入群聊
#define DATAINF 0x02 // 发送群聊消息

#define LOGIN 0xfA   // 登陆验证
#define CHAT 0x07    // 消息包
#define DATA 0x0f    // 数据包
#define DATAEND 0xAA // 数据包发送完毕标记

// 握手 客户端给服务器发握手包（包内数据包含接下来数据量，数据类型，目标群，自己ID名字等(分建不同用户)），服务器准备好线程接收消息，准备工作完成后回复客户端握手包。
// 此时客户端转发数据，直到转发了DATAEND表示此次传输结束

// 记录线程数目
int pthread_num = 0;

// 线程自管理
struct thread_manage
{
    int sock;
    struct sockaddr_in send_addr;
};

#pragma pack(push, 8) // 确保双方字节对其

struct date
{
    char file_type; // 此包的传输的数据消息类型
    size_t grep_id;
    size_t sleek; // 此包数据的指针的位置
    size_t size;  // 数据包中 DATA 的字节数
    char talk[_DATAPAEK];
};
#pragma pack(pop)
class SQLiteDB
{
public:
    SQLiteDB(const char *db_file)
    {
        sqlite3_open(db_file, &db);
    }

    // 创建表
    void createTable(const char *table_name)
    {

        std::string query = "CREATE TABLE IF NOT EXISTS " +
                            std::string(table_name) +
                            " ("
                            "ID INTEGER PRIMARY KEY, "
                            "name TEXT, "
                            "send_addr_port INTEGER, "
                            "send_addr_ip TEXT, "
                            "send_addr_family INTEGER)";

        sqlite3_exec(db, query.c_str(), NULL, NULL, NULL);
    }

    void createTable(int grep_id)
    {

        std::string query = "CREATE TABLE IF NOT EXISTS grep_" +
                            std::to_string(grep_id) +
                            " ("
                            "ID INTEGER PRIMARY KEY, "
                            "name TEXT, "
                            "send_addr_port INTEGER, "
                            "send_addr_ip TEXT, "
                            "send_addr_family INTEGER);";

        sqlite3_exec(db, query.c_str(), NULL, NULL, NULL);
    }

    // 删除表
    void dropTable(const char *table_name)
    {

        std::string query = "DROP TABLE IF EXISTS ";
        query += table_name;

        sqlite3_exec(db, query.c_str(), NULL, NULL, NULL);
    }

    // 查找此表
    bool tableExists(const std::string &table_name)
    {
        sqlite3_stmt *stmt;
        std::string query = "SELECT name FROM sqlite_master WHERE type='table' AND name='?'";

        sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);
        sqlite3_bind_text(stmt, 1, table_name.c_str(), -1, SQLITE_STATIC);

        bool exists = false;
        if (sqlite3_step(stmt) == SQLITE_ROW)
        {
            exists = true;
        }

        sqlite3_finalize(stmt);
        return exists;
    }

    // 插入用户（用户进群）
    void insert(int grep_id, const user_inf &user)
    {

        std::string table_name = "grep_" + std::to_string(grep_id);

        if (tableExists(table_name.c_str())) // 先查询表是否存在
        {
            std::cerr << "无此群创建群聊" << std::endl;
            createTable(table_name.c_str());
        }

        sqlite3_stmt *stmt;
        std::string query = "INSERT INTO " + table_name + " VALUES (?, ?, ?, ?, ?)";

        sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);

        // 绑定用户数据
        sqlite3_bind_int(stmt, 1, user.ID);
        sqlite3_bind_text(stmt, 2, user.name, -1, SQLITE_STATIC);
        sqlite3_bind_int(stmt, 3, user.send_addr.sin_port);
        sqlite3_bind_text(stmt, 4, inet_ntoa(user.send_addr.sin_addr), -1, SQLITE_TRANSIENT);
        sqlite3_bind_int(stmt, 5, user.send_addr.sin_family);

        sqlite3_step(stmt);
        sqlite3_finalize(stmt);
    }

    // 通过ID查找该用户
    user_inf getUserByID(int id, int user_id)
    {

        std::string table_name = "grep_" + std::to_string(id);

        sqlite3_stmt *stmt;
        std::string query = "SELECT * FROM " + table_name + " WHERE ID = ?";

        sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);

        // 绑定用户ID
        sqlite3_bind_int(stmt, 1, user_id);

        user_inf user = {0};
        if (sqlite3_step(stmt) == SQLITE_ROW)
        {
            user.ID = sqlite3_column_int(stmt, 0);
            strcpy(user.name, (const char *)sqlite3_column_text(stmt, 1));

            user.send_addr.sin_port = sqlite3_column_int(stmt, 2);
            user.send_addr.sin_addr.s_addr = inet_addr((const char *)sqlite3_column_text(stmt, 3));
            user.send_addr.sin_family = sqlite3_column_int(stmt, 4);
        }
        sqlite3_finalize(stmt);

        return user;
    }

    // 遍历群聊
    void traverseTable_send(int grep_id, user_inf &user, const char *buf, size_t n)
    {
        std::cerr << "traverseTable_send";

        std::string query = "SELECT * FROM grep_" + std::to_string(grep_id);

        sqlite3_stmt *stmt;
        // sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);
        if (sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL) != SQLITE_OK)
        {
            std::cerr << "执行到此";
            // 失败处理
            return;
        }

        while (sqlite3_step(stmt) == SQLITE_ROW)
        {
            std::cerr << "sqlite3_step :: while";

            if (sqlite3_column_int(stmt, 0) == user.ID)
            {
            }
            user_inf tmpuser;
            tmpuser.ID = sqlite3_column_int(stmt, 0);
            strcpy(tmpuser.name, (const char *)sqlite3_column_text(stmt, 1));
            tmpuser.send_addr.sin_port = sqlite3_column_int(stmt, 2);
            tmpuser.send_addr.sin_addr.s_addr = inet_addr((const char *)sqlite3_column_text(stmt, 3));
            tmpuser.send_addr.sin_family = sqlite3_column_int(stmt, 4);

            int sock = socket(AF_INET, SOCK_STREAM, 0);

            struct timeval tv;
            tv.tv_sec = 1;
            tv.tv_usec = 0;

            setsockopt(sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv);

            // 连接用户

            if (connect(sock, (struct sockaddr *)&tmpuser.send_addr, sizeof(tmpuser.send_addr)))
            {
                continue;
            }

            // 发送数据
            date dat = {0};
            dat.file_type = SENDTO;
            send(sock, &dat, sizeof(dat), 0);

            if (-1 == recv(sock, &dat, sizeof(dat), 0))
            {
                close(sock);
                continue;
            }

            int size = 0;
            int sleek = 0;

            while (n > 0)
            {
                dat.file_type = DATA;
                size = n > _DATAPAEK ? _DATAPAEK : _DATAPAEK - n;

                memcpy(dat.talk, buf, size);
                buf += size;

                if (-1 == recv(sock, &dat, sizeof(dat), 0))
                {
                    continue;
                }

                n -= _DATAPAEK;
            }

            dat.file_type = SENDOUT;
            recv(sock, &dat, sizeof(dat), 0);

            close(sock);
        }
        sqlite3_finalize(stmt);
    }

    void updateUser(int grep_id, const user_inf &user)
    {
        std::string table_name = "grep_" + std::to_string(grep_id);

        if (!tableExists(table_name))
        {
            // 表不存在，创建新表
            createTable(grep_id);
        }

        sqlite3_stmt *stmt;
        std::string query = "UPDATE " + table_name + " SET name = ?, send_addr_port = ?, send_addr_ip = ?, send_addr_family = ? WHERE ID = ?";

        sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);

        // 绑定用户数据
        sqlite3_bind_text(stmt, 1, user.name, -1, SQLITE_STATIC);
        sqlite3_bind_int(stmt, 2, user.send_addr.sin_port);
        sqlite3_bind_text(stmt, 3, inet_ntoa(user.send_addr.sin_addr), -1, SQLITE_TRANSIENT);
        sqlite3_bind_int(stmt, 4, user.send_addr.sin_family);
        sqlite3_bind_int(stmt, 5, user.ID);

        sqlite3_step(stmt);
        sqlite3_finalize(stmt);
    }

    // 更新用户数据
    void updateOrInsertUser(int grep_id, const user_inf &user)
    {
        std::string table_name = "grep_" + std::to_string(grep_id);

        if (tableExists(table_name))
        {
            user_inf tmp = getUserByID(grep_id, user.ID);
            // 表存在，检查用户是否存在
            if (tmp.ID == user.ID)
            {
                // 用户存在，更新用户数据
                updateUser(grep_id, user);
            }
            else
            {
                // 用户不存在，插入新用户数据
                insert(grep_id, user);
            }
        }
        else
        {
            // 表不存在，创建新表并插入新用户数据
            createTable(grep_id);
            insert(grep_id, user);
        }
    }

    bool tableExists(int grep_id);
    void deleteByID(int grep_id, int user_id);
    // 删除表中数据

private:
    sqlite3 *db;
};

void SQLiteDB::deleteByID(int grep_id, int user_id)
{

    sqlite3_stmt *stmt;
    std::string query = "DELETE FROM grep_" + std::to_string(grep_id) + " WHERE ID = ?";

    sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);

    // 绑定要删除的用户ID 绑定stmt
    sqlite3_bind_int(stmt, 1, user_id);

    // 执行语句
    sqlite3_step(stmt);
    sqlite3_finalize(stmt);
}

bool SQLiteDB::tableExists(int grep_id)
{
    sqlite3_stmt *stmt;
    std::string query = "SELECT name FROM sqlite_master WHERE type='table' AND name = ?;";
    sqlite3_prepare_v2(db, query.c_str(), -1, &stmt, NULL);
    std::string tableName = "grep_" + std::to_string(grep_id);
    sqlite3_bind_text(stmt, 1, tableName.c_str(), -1, SQLITE_STATIC);

    bool exists = false;
    if (sqlite3_step(stmt) == SQLITE_ROW)
    {
        exists = true;
    }

    sqlite3_finalize(stmt);
    return exists;
}

class TCP_CHAT
{
private:
public:
    TCP_CHAT();
    ~TCP_CHAT();
};

TCP_CHAT::TCP_CHAT()
{
}

TCP_CHAT::~TCP_CHAT()
{
}

void *recv_thread(void *arg);

SQLiteDB grep("serve_chat.db");

int main()
{
    // 接收端套接字
    int recv_sock_listen = socket(AF_INET, SOCK_STREAM, 0), client_sock;

    // // 发送套接字
    // int send_sock_listen = socket(AF_INET, SOCK_DGRAM, 0);

    if (recv_sock_listen == -1)
    {
        perror("socket error");
        exit(EXIT_FAILURE);
    }

    // 设置套接字的SO_REUSADDR 的属性为 1，以开启地址复用
    int val = 1;
    setsockopt(recv_sock_listen, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
    // 绑定
    struct sockaddr_in recv_server; // 接收

    recv_server.sin_family = AF_INET;
    recv_server.sin_addr.s_addr = INADDR_ANY;
    recv_server.sin_port = htons(RECV_PORT);

    if (-1 == bind(recv_sock_listen, (struct sockaddr *)&recv_server, sizeof(recv_server)))
    {
        perror("bind error");
        exit(EXIT_FAILURE);
    }

    // 第 3 步：监听
    if (-1 == listen(recv_sock_listen, 20)) // 第 2 个参数表示监听等待队列的长度
    {
        perror("listen error");
        exit(EXIT_FAILURE);
    }

    int c = sizeof(struct sockaddr_in);

    int *new_sock = nullptr;
    thread_manage *new_client = nullptr;

    struct sockaddr_in client_addr;
    socklen_t addr_len = sizeof(client_addr);

    while ((client_sock = accept(recv_sock_listen, (struct sockaddr *)&client_addr, &addr_len)))
    {
        // 创建新线程处理客户端
        pthread_t sniffer_thread;

        new_client = new thread_manage();
        new_client->send_addr = client_addr;
        new_client->sock = client_sock;

        if (pthread_create(&sniffer_thread, NULL, recv_thread, (void *)new_client))
        {
            perror("线程创建失败");
            continue;
        }
        pthread_num++;
        while (pthread_num > 20) // 后续换成锁
        {
            // 延时 1ms 自旋锁
            std::this_thread::sleep_for(std::chrono::milliseconds(1));
        }
    }

    return 0;
}

void *recv_thread(void *arg)
{
    pthread_detach(pthread_self());

    thread_manage *user_mag = (thread_manage *)arg;

    date dat = {0};

    struct timeval tv;
    tv.tv_sec = 1;
    tv.tv_usec = 0;

    // setsockopt(user_mag->sock, SOL_SOCKET, SO_RCVTIMEO, (const char *)&tv, sizeof tv);

    if (-1 == recv(user_mag->sock, &dat, sizeof(dat), 0)) // 接收第一个数据包
    {
        std::cerr << std::endl
                  << "超时" << std::endl;
    }

    user_inf user; // 记录用户信息
    user.ID = dat.size;
    strcpy(user.name, dat.talk);
    user.send_addr = user_mag->send_addr;

    std::cout << "线程创建成功\n"
              << "有用户" << user.ID
              << user.name << "群聊：" << dat.grep_id << std::endl;

    if (dat.file_type == ADDGREP)
    {

        dat.file_type = SENDOUT;
        // send(user_mag->sock, &dat, sizeof(dat), 0); // 返回成功信息

        user_inf tmp = {0};

        // 更新用户
        grep.updateOrInsertUser(dat.grep_id, user);
        // if (tmp.ID != user.ID)
        // {
        //     std::cerr << "人员入群" << std::endl;
        //     grep.insert(dat.grep_id, user); // 用户数据存数据库
        // }
        // else
        // {
        //     std::cerr << "人员在群" << std::endl;
        // }
    }
    else if (dat.file_type == CHAT && dat.sleek < 1000000) // 聊天包
    {
        size_t Size = dat.sleek;
        int grep_id = dat.grep_id;
        std::cerr << "传输大小" << Size << std::endl;

        char *buf = new char[Size + 2]();
        dat.file_type = SENDTO;
        // send(user_mag->sock, &dat, sizeof(dat), 0); // 回复消息

        int ret = 0;

        while (-1 != (ret = recv(user_mag->sock, &dat, sizeof(dat), 0)))
        {
            std::cerr << "此次数据包大小" << dat.size << "指针位置" << dat.sleek << std::endl;

            if (dat.file_type != CHAT)
            {
                std::cerr << "结束" << std::endl;
                break;
            }

            memcpy(buf, dat.talk, dat.size);
        }

        std::cerr << "转发内容" << buf << std::endl;

        if (ret == -1)
        {
            std::cerr << "error 客户端断开连接";
            pthread_num--;
            delete[] buf;
            pthread_exit(nullptr);
        }

        grep.traverseTable_send(grep_id, user, buf, Size);
        delete[] buf;
    }

    std::cerr << "线程结束";
    delete user_mag;
    close(user_mag->sock);
    pthread_num--;
    pthread_exit(nullptr);
}